In this column:
set 1,(IY+05)This will make it so the row of pixels directly underneath the text is also black, centering the text on the black background since there is already a row of black pixels directly above the text. If you do not set this bit, this row of pixels will not be black, and the bottom of your text will look chopped off. This only applies when you use ROM_CALL(D_ZM_STR). It looks the same when you use ROM_CALL(D_ZT_STR) whether you set this bit or not. It is important that you reset this bit at some point before you exit the program.
res 1,(IY+05)If you don't do this, there is a possiblity that when other program are run, the calculator will crash. This was a fatal bug in an earlier version of my game Blockbuster. If someone played ZTetris after Blockbuster, their calculator crashed, because I had forgotten to reset the first bit in (IY+05).
G_NONE | $00 | NO KEY |
G_DOWN | $01 | DOWN |
G_LEFT | $02 | LEFT |
G_RIGTH G_RIGHT (Crash only) | $03 | RIGHT |
G_UP | $04 | UP |
G_ENTER | $09 | ENTER |
G_PLUS | $0A | + |
G_MINUS | $0B | - |
G_TIMES | $0C | * |
G_DIV | $0D | / |
G_POWER (Ash only) G_CARROT (Crash only) | $0E | ^ |
G_CLEAR | $0F | CLEAR |
G_NEG | $11 | (-) |
G_3 | $12 | 3 |
G_6 | $13 | 6 |
G_9 | $14 | 9 |
G_RPARAN (Ash only) G_PARENR (Crash only) | $15 | ) |
G_TAN | $16 | TAN |
G_VARS | $17 | VARS |
G_PERIODE (Ash only) G_PERIOD (Crash only) | $19 | . |
G_2 | $1A | 2 |
G_5 | $1B | 5 |
G_8 | $1C | 8 |
G_LPARAN (Ash only) G_PARENL (Crash only) | $1D | ( |
G_COS | $1E | COS |
G_PRGM | $1F | PRGM |
G_STAT | $20 | STAT |
G_0 | $21 | 0 |
G_1 | $22 | 1 |
G_4 | $23 | 4 |
G_7 | $24 | 7 |
G_COMMA | $25 | , |
G_SIN | $26 | SIN |
G_MATRIX | $27 | MATRIX |
G_XTO | $28 | x,T,theta| |
G_ON | $29 | ON |
G_STO | $2A | STO> |
G_LN | $2B | LN |
G_LOG | $2C | LOG |
G_SQR | $2D | X^2 |
G_INVERSE (Ash only) G_INVE (Crash only) | $2E | X^-1 |
G_MATH | $2F | MATH |
G_ALPHA | $30 | ALPHA |
G_GRAPH | $31 | GRAPH |
G_TRACE | $32 | TRACE |
G_ZOOM | $33 | ZOOM |
G_WINDOW | $34 | WINDOW |
G_YEDIT | $35 | Y= |
G_2nd | $36 | 2nd |
G_MODE | $37 | MODE |
G_DEL | $38 | DEL |
The second method should only be done in Crash. While call GET_KEY merely loads the most recent keypress into the a register, this next function actually waits for you to press a key. And while it is waiting, you can adjust the contrast, press 2nd and ALPHA and see the appropriate cursors light up, and turn off the calculator. If you use this function in Ash and turn of the calculator, your 82 will crash. Ash calls this function ROM_CALL(KEY_HAND). In earlier versions of Ash, before they added relocation, it worked just fine. But with the relocation feature, which was with version 3.0, KEY_HAND became extremely impractical. One of the nice features about Crash is that it fixes this problem. Instead of calling the ROM directly, you call a function in Crash itself which first derelocates the program, then calls the ROM function. So if the calc is turned off (or automatically powers down, which also happens when this function is used), it will be safe from crashing because the program was no longer relocated. To call this function in Crash, use this code.
call CR_KHANDThis also stores a value in the a register. However, it is completely different than the one we would get if we used GET_KEY. And since CR_KHAND reads 2nd and alpha functions as well as just the regular functions of a key, there are three times as many possibilities as GET_KEY for what we end up having in the a register. Following is a table of all these different possibilties, with the name of the key, the function, the decimal value found in the a register, and the alias in crash82.inc. Remember, only use this function in Crash.
K_RIGTH | 1 | RIGHT | RIGHT |
K_RIGHT | 1 | RIGHT | RIGHT |
K_LEFT | 2 | LEFT | LEFT |
K_UP | 3 | UP | UP |
K_DOWN | 4 | DOWN | DOWN |
K_ENTER | 5 | ENTER | ENTER |
K_CLEAR | 6 | CLEAR | CLEAR |
K_DEL | 7 | DEL | DEL |
K_INS | 8 | DEL | INS |
K_RCL | 9 | STO> | RCL |
K_ENTRY | 10 | ENTER | ENTRY |
K_BOL | 11 | LEFT | BOL |
K_EOL | 12 | RIGHT | EOL |
K_PRGM | 45 | PRGM | PRGM |
K_ZOOM | 46 | ZOOM | ZOOM |
K_DRAW | 47 | PRGM | DRAW |
K_PLOT | 48 | Y= | STAT PLOT |
K_MATH | 49 | MATH | MATH |
K_TEST | 50 | MATH | TEST |
K_VARS | 52 | VARS | VARS |
K_MEM | 53 | + | MEM |
K_MATRIX | 54 | MATRIX | MATRIX |
K_STAT | 55 | STAT | STAT |
K_Y-VARS | 56 | VARS | Y-VARS |
K_ANGLE | 57 | MATRIX | ANGLE |
K_LIST | 58 | STAT | LIST |
K_CALC | 59 | TRACE | CALC |
K_QUIT | 64 | MODE | QUIT |
K_LINK | 65 | X,T,theta | LINK |
K_GRAPH | 69 | GRAPH | GRAPH |
K_MODE | 70 | MODE | MODE |
K_WINDOW | 73 | WINDOW | WINDOW |
K_YEDIT | 74 | Y= | Y= |
K_TABLE | 75 | GRAPH | TABLE |
K_TBLSET | 76 | WINDOW | TblSet |
K_TRACE | 93 | TRACE | TRACE |
K_PLUS | 129 | + | + |
K_MINUS | 130 | - | - |
K_TIMES | 131 | * | * |
K_DIV | 132 | / | / |
K_POWER | 133 | ^ | ^ |
K_LPAREN | 134 | ( | ( |
K_RPAREN | 135 | ) | ) |
K_LBRACK | 136 | * | [ |
K_RBRACK | 137 | - | ] |
K_STO | 139 | STO> | STO> |
K_COMMA | 140 | , | , |
K_NEG | 141 | (-) | (-) |
K_PERIOD | 142 | . | . |
K_0 | 143 | 0 | 0 |
K_1 | 144 | 1 | 1 |
K_2 | 145 | 2 | 2 |
K_3 | 146 | 3 | 3 |
K_4 | 147 | 4 | 4 |
K_5 | 148 | 5 | 5 |
K_6 | 149 | 6 | 6 |
K_7 | 150 | 7 | 7 |
K_8 | 151 | 8 | 8 |
K_9 | 152 | 9 | 9 |
K_EE | 153 | , | EE |
K_SEMI | 154 | 0 | ; |
K_A | 155 | MATH | A |
K_B | 156 | MATRIX | B |
K_C | 157 | PRGM | C |
K_D | 158 | X^-1 | D |
K_E | 159 | SIN | E |
K_F | 160 | COS | F |
K_G | 161 | TAN | G |
K_H | 162 | ^ | H |
K_I | 163 | X^2 | I |
K_J | 164 | , | J |
K_K | 165 | ( | K |
K_L | 166 | ) | L |
K_M | 167 | / | M |
K_N | 168 | LOG | N |
K_O | 169 | 7 | O |
K_P | 170 | 8 | P |
K_Q | 171 | 9 | Q |
K_R | 172 | * | R |
K_S | 173 | LN | S |
K_T | 174 | 4 | T |
K_U | 175 | 5 | U |
K_V | 176 | 6 | V |
K_W | 177 | - | W |
K_X | 178 | STO> | X |
K_Y | 179 | 1 | Y |
K_Z | 180 | 2 | Z |
K_XTO | 181 | X,T,theta | X,T,theta |
K_PI | 182 | ^ | Pi |
K_INVERSE | 183 | X^-1 | X^-1 |
K_SIN | 184 | SIN | SIN |
K_ASIN | 185 | SIN | SIN^-1 |
K_COS | 186 | COS | COS |
K_ACOS | 187 | COS | COS^-1 |
K_TAN | 188 | TAN | TAN |
K_ATAN | 189 | TAN | TAN^-1 |
K_SQR | 190 | X^2 | X^2 |
K_SQRT | 191 | X^2 | SQRT |
K_LN | 192 | LN | LN |
K_EX | 193 | LN | e^X |
K_LOG | 194 | LOG | LOG |
K_TENP | 195 | LOG | 10^X |
K_ANS | 198 | (-) | ANS |
K_COLON | 199 | . | : |
K_QUEST | 203 | (-) | ? |
K_QUOTE | 204 | + | " |
K_THETA | 205 | 3 | THETA |
K_LBRACE | 237 | ( | { |
K_RBRACE | 238 | ) | } |
K_ABS | 244 | X^-1 | ABS |
K_L1 | 245 | 1 | L1 |
K_L2 | 246 | 2 | L2 |
K_L3 | 247 | 3 | L3 |
K_L4 | 248 | 4 | L4 |
K_L5 | 249 | 5 | L5 |
K_L6 | 250 | 6 | L6 |
K_n | 251 | 9 | n |
K_Vn1 | 252 | 8 | Vn-1 |
K_Un1 | 253 | 7 | Un-1 |
Phew, that's a lot, huh? Try formatting it into HTML, too! :P Anyways, the third method of reading keypresses is to read the keyboard port directly, which is a little advanced for us right now. After a few more lessons, we'll get to that.
Okay, so let's look at a little snippet of our code from the Hello program we wrote in the last column.
Loop: call GET_KEY cp G_ENTER ret z jr LoopOkay, there's our new friend GET_KEY! So what we did was we read the most recent keypress and store that into the a register. We then use the cp command to compare a with G_ENTER, which is the alias for $09 given in ti82.h and crash82.inc. If Enter was the most recent key pressed, then the value of a would indeed be $09. With the cp command, if a is equal to the value we're comparing it to, the zero flag is set. What? The rest of this code is a little hard to understand without learning some more stuff . . .
Label: asm code here
Jr is small and fast, but can only go so far. Jp takes up more memory, is slower, but can go really far. So, when in doubt, use jr. However, when compiling your program, if you get an error in tasm saying "Range of relative branch exceeded," you need to change one of your jr's to a jp. So let's say you want to jump to a label named "Label". Depending on far away Label is, you'll either use
jr Labelor
jp LabelNow, here's where that zero flag I mentioned when we were looking at the code from our Hello program comes in. You can also make your jumps conditional. If you use
jr z,Labelyou will only jump to Label if the zero flag is set. To jump to Label if the zero flag is not set, use
jr nz,Label
So let's say you have this:
call Subroutine ... code ... Subroutine: ... code ... retWhen the TI-82 encounters call Subroutine, it will jump to the code at "Subroutine" and run it until it encounters ret. When this occurs, it will jump right back to right after call Subroutine.
Just like the jumps, there are conditional calls and rets: i.e.
call z,Subroutine call nz,Subroutine ret z ret nzThis is why we have to put ret at the end of an assembly program to return to the shell. The shell used call to run the program, and in order to return to the shell, we have to use ret.
Another little note about call. You probably noticed above that it is call GET_KEY and ROM_CALL(D_ZT_STR). This is because GET_KEY exists at the same point in all of the different TI-82 ROM versions, so it can be called directly. However, D_ZT_STR's location varies depending on your ROM version. For this reason, the shell has to determine which version you have and then jump to the proper location. This is why you have to use ROM_CALL for most, but not all, ROM functions.
Knowing all of this, we can finally completely understand the loop used in the last column.
Loop: call GET_KEY cp G_ENTER ret z jr Loop
Okay, we've called GET_KEY, so the a register now contains the value of the last key pressed (according to the first table shown above). So if [ENTER] was pressed, the zero flag would be set. Ret z is a conditional return, so the program will return to the shell only if the zero flag is set (i.e. [ENTER] was pressed). And the final command, jr Loop, will jump you back to Loop, where it all starts over again.
Well, both of these tutorials are now updated for Ash v3.0 and Crash v1.6. The next column will deal with some new commands.